﻿using System.Collections.Generic;
using XNAFight.Characters;
using XNAFight.Engine;
using XNAFight.Engine.Inputs;
using Microsoft.Xna.Framework.Input;

namespace XNAFight.Engine.Inputs
{
    /// Donne des fonctions statiques pour interpreter les inputs utilisés durant un combat
    class FightInputInterpreter
    {
        private bool last_left;
        private bool last_right;
        private bool last_down;
        private bool last_up;

        public FightInputInterpreter()
        {
            last_left = false;
            last_right = false;
            last_down = false;
            last_up = false;
        }

        /// Donne la liste des mouvements de base (voir XNAFight.Engine.Moves) effectués au clavier à la dernière frame 
        /// selon la configuration des raccourcis _kbd_configuration et selon l'orientation du personnage _char_looking_on_the_right
        public List<BMove> getKeyboardMoves(InGameKeyboardConfiguration _keyboard_configuration, bool _char_looking_on_the_right)
        {
            List<BMove> last_moves = new List<BMove>();

            #region PUNCH
            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.LPunch))
                last_moves.Add(BMove.LPUNCH);

            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.MPunch))
                last_moves.Add(BMove.MPUNCH);

            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.HPunch))
                last_moves.Add(BMove.HPUNCH);
            #endregion
            
            #region KICK
            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.LKick))
                last_moves.Add(BMove.LKICK);

            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.MKick))
                last_moves.Add(BMove.MKICK);

            if (InputState.isNewKeyPressed((Keys)_keyboard_configuration.HKick))
                last_moves.Add(BMove.HKICK);
            #endregion

            #region PRIORITES DES DIRECTIONS

            bool left = false;
            bool right = false;
            bool down = false;
            bool up = false;

            #region DROITE VS GAUCHE

            // Tous les cas pour lesquels le joueur est en train d'appuyer à gauche
            if (InputState.isKeyPressed(Keys.Left))
            {
                // Si droite et gauche sont en train d'etre appuyés en meme temps, il faut déterminer lequel a la priorité
                // Le dernier bouton sur lequel le joueur a appuyé a la priorité
                if (InputState.isKeyPressed(Keys.Right))
                {
                    // On regarde dans quelle direction le joueur a appuyé en dernier
                    if (InputState.isNewKeyPressed(Keys.Left))
                    {
                        left = true;
                        // Note : Si le joueur appuie simultanément dans les deux direction on donne priorité à gauche (on evite le blocage ultime)
                    }
                    else if (InputState.isNewKeyPressed(Keys.Right))
                    {
                        right = true;
                    }
                    else
                    {
                        left = last_left;
                        right = last_right;
                    }
                }
                else
                {
                    left = true;
                }
            }

            // Si le joueur appuie à droite (mais pas à gauche)
            else if (InputState.isKeyPressed(Keys.Right))
            {
                right = true;
            }

            #endregion

            #region HAUT VS BAS

            // Tous les cas pour lesquels le joueur est en train d'appuyer en bas
            if (InputState.isKeyPressed(Keys.Down))
            {
                // Si bas et haut sont en train d'etre appuyés en meme temps, il faut déterminer lequel a la priorité
                // Le dernier bouton sur lequel le joueur a appuyé a la priorité
                if (InputState.isKeyPressed(Keys.Up))
                {
                    // On regarde dans quelle direction le joueur a appuyé en dernier
                    if (InputState.isNewKeyPressed(Keys.Down))
                    {
                        down = true;
                        // Note : Si le joueur appuie simultanément dans les deux direction on donne priorité au bas
                    }
                    else if (InputState.isNewKeyPressed(Keys.Up))
                    {
                        up = true;
                    }
                    else
                    {
                        up = last_up;
                        down = last_down;
                    }
                }
                else
                {
                    down = true;
                }
            }

            // Si le joueur appuie en haut (mais pas en bas)
            else if (InputState.isKeyPressed(Keys.Up))
            {
                up = true;
            }

            #endregion

            #endregion

            #region DOWN, DOWN+BACK, DOWN+FORWARD
            if (down)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                {
                    if (left)
                        last_moves.Add(BMove.DOWN_BACK);
                    else if (right)
                        last_moves.Add(BMove.DOWN_FORWARD);
                    else
                        last_moves.Add(BMove.DOWN);
                }
                else
                {
                    if (left)
                        last_moves.Add(BMove.DOWN_FORWARD);
                    else if (right)
                        last_moves.Add(BMove.DOWN_BACK);
                    else
                        last_moves.Add(BMove.DOWN);
                }
            }
            #endregion

            #region UP, UP+BACK, UP+FORWARD
            else if (up)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                {
                    if (left)
                        last_moves.Add(BMove.UP_BACK);
                    else if (right)
                        last_moves.Add(BMove.UP_FORWARD);
                    else
                        last_moves.Add(BMove.UP);
                }
                else
                {
                    if (left)
                        last_moves.Add(BMove.UP_FORWARD);
                    else if (right)
                        last_moves.Add(BMove.UP_BACK);
                    else
                        last_moves.Add(BMove.UP);
                }
            }
            #endregion

            #region BACK, FORWARD
            else if (right)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                    last_moves.Add(BMove.FORWARD);
                else
                    last_moves.Add(BMove.BACK);
            }
            else if (left)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                    last_moves.Add(BMove.BACK);
                else
                    last_moves.Add(BMove.FORWARD);
            }
            #endregion

            last_left = left;
            last_right = right;
            last_down = down;
            last_up = up;

            return last_moves;
        }

        /// Donne la liste des mouvements de base (voir XNAFight.Engine.Moves) effectués au pad à la dernière frame 
        /// selon la configuration des raccourcis _pad_configuration et selon l'orientation du personnage _char_looking_on_the_right
        public List<BMove> getPadMoves(InGamePadConfiguration _pad_configuration, bool _char_looking_on_the_right)
        {
            List<BMove> last_moves = new List<BMove>();

            #region PUNCH
            if (InputState.isButtonPressed((Buttons)_pad_configuration.LPunch, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.LPUNCH);

            if (InputState.isButtonPressed((Buttons)_pad_configuration.MPunch, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.MPUNCH);

            if (InputState.isButtonPressed((Buttons)_pad_configuration.HPunch, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.HPUNCH);
            #endregion

            #region KICK
            if (InputState.isButtonPressed((Buttons)_pad_configuration.LKick, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.LKICK);

            if (InputState.isButtonPressed((Buttons)_pad_configuration.MKick, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.MKICK);

            if (InputState.isButtonPressed((Buttons)_pad_configuration.HKick, _pad_configuration.PlrIndex))
                last_moves.Add(BMove.HKICK);
            #endregion

            #region PRIORITES DES DIRECTIONS

            bool left = false;
            bool right = false;
            bool down = false;
            bool up = false;

            #region DROITE VS GAUCHE

            // la croix directionnelle a priorité sur le stick, on verifie donc d'abord la croix puis on verifie le stick si aucune direction n'a été donnée sur la croix
            if (InputState.isButtonPressed(Buttons.DPadLeft, _pad_configuration.PlrIndex))
            {
                left = true;
            }
            else if (InputState.isButtonPressed(Buttons.DPadRight, _pad_configuration.PlrIndex))
            {
                right = true;
            }

            if (!left && !right)
            {
                if (InputState.isLeftStickOnLeft(_pad_configuration.PlrIndex))
                {
                    left = true;
                }
                else if (InputState.isLeftStickOnRight(_pad_configuration.PlrIndex))
                {
                    right = true;
                }
            }

            #endregion

            #region HAUT VS BAS

            // la croix directionnelle a priorité sur le stick, on verifie donc d'abord la croix puis on verifie le stick si aucune direction n'a été donnée sur la croix
            if (InputState.isButtonPressed(Buttons.DPadDown, _pad_configuration.PlrIndex))
            {
                down = true;
            }
            else if (InputState.isButtonPressed(Buttons.DPadUp, _pad_configuration.PlrIndex))
            {
                up = true;
            }

            if (!down && !up)
            {
                if (InputState.isLeftStickDowned(_pad_configuration.PlrIndex))
                {
                    down = true;
                }
                else if (InputState.isLeftStickUpped(_pad_configuration.PlrIndex))
                {
                    up = true;
                }
            }

            #endregion

            #endregion

            #region DOWN, DOWN+BACK, DOWN+FORWARD
            if (down)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                {
                    if (left)
                        last_moves.Add(BMove.DOWN_BACK);
                    else if (right)
                        last_moves.Add(BMove.DOWN_FORWARD);
                    else
                        last_moves.Add(BMove.DOWN);
                }
                else
                {
                    if (left)
                        last_moves.Add(BMove.DOWN_FORWARD);
                    else if (right)
                        last_moves.Add(BMove.DOWN_BACK);
                    else
                        last_moves.Add(BMove.DOWN);
                }
            }
            #endregion

            #region UP, UP+BACK, UP+FORWARD
            else if (up)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                {
                    if (left)
                        last_moves.Add(BMove.UP_BACK);
                    else if (right)
                        last_moves.Add(BMove.UP_FORWARD);
                    else
                        last_moves.Add(BMove.UP);
                }
                else
                {
                    if (left)
                        last_moves.Add(BMove.UP_FORWARD);
                    else if (right)
                        last_moves.Add(BMove.UP_BACK);
                    else
                        last_moves.Add(BMove.UP);
                }
            }
            #endregion

            #region BACK, FORWARD
            else if (right)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                    last_moves.Add(BMove.FORWARD);
                else
                    last_moves.Add(BMove.BACK);
            }
            else if (left)
            {
                // BACK et FORWARD sont definis en fonction de l'orientation du personnage : _char_looking_on_the_right
                if (_char_looking_on_the_right)
                    last_moves.Add(BMove.BACK);
                else
                    last_moves.Add(BMove.FORWARD);
            }
            #endregion

            last_left = left;
            last_right = right;
            last_down = down;
            last_up = up;

            return last_moves;
        }
    }
}
